import 'dart:convert';
import 'dart:io';
import 'package:curl_logger_dio_interceptor/curl_logger_dio_interceptor.dart';
import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/route_manager.dart';
import 'package:logmanager/utils/string_ext.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';

import '../../bean/user.dart';
import '../../routers/router.dart';
import '../http_code.dart';
import '../request_config.dart';
import 'base_res.dart';
import 'dio_method.dart';

class DioManager {
  /// 单利模式
  Dio? _dio;
  final Map<String, dynamic> _headers = {};

  factory DioManager() => _instance;

  DioManager._inernal() {
    if (_dio == null) {
      BaseOptions baseOptions = BaseOptions(
          baseUrl: RequestConfig.baseUrl,
          contentType: Headers.jsonContentType,
          responseType: ResponseType.json,
          receiveDataWhenStatusError: false,
          connectTimeout: const Duration(seconds: RequestConfig.connectTimeout),
          receiveTimeout: const Duration(seconds: RequestConfig.receiveTimeout),
          headers: _headers);
      _dio = Dio(baseOptions)
        ..interceptors.add(PrettyDioLogger(
          requestHeader: true,
          requestBody: true,
          responseBody: true,
          responseHeader: true,
          compact: true,
        ))
        ..interceptors.add(CurlLoggerDioInterceptor(printOnSuccess: true))
        // ..interceptors.add(
        //   InterceptorsWrapper(
        //     onRequest: (options, handler) {},
        //     onResponse: (response, handler) {},
        //     onError: (DioException e, handler) {},
        //   ),
        // )
        ..options.validateStatus = (status) => true;

      /// 若设备为IOS或Android 忽略Https校验 web不需要暂时毙掉
      if (!kIsWeb) {
        _dio?.httpClientAdapter = IOHttpClientAdapter(
          createHttpClient: () {
            final HttpClient client =
                HttpClient(context: SecurityContext(withTrustedRoots: false));
            client.badCertificateCallback =
                ((X509Certificate cert, String host, int port) => true);
            return client;
          },
        );
      }
      ;
    }
  }

  static late final DioManager _instance = DioManager._inernal();

  Future request<T>(String url,
      {DioMethod method = DioMethod.POST,
      Map<String, dynamic>? queryParameters,
      data,
      Map<String, dynamic>? headers,
      Function(T data)? success,
      Function(String errorMsg)? failMsg,
      Function(BaseRes baseResponse)? baseResponse,
      showLoading = false, // 默认显示网络加载loading
      loadingMsg = "加载中...", // loading文案
      toastFailMsg = true, // 默认吐司网络请求错误
      Function(int count, int total)? onSendProgress // 文件上传进度监听，只有Post方式才能回调该函数
      }) async {
    if (showLoading) {
      // EasyLoading.show(status: loadingMsg);
      EasyLoading.show(
          status: loadingMsg,
          maskType: EasyLoadingMaskType.black,
          dismissOnTap: false);
    }
    // 动态添加headers头
    Map<String, dynamic> _headers = Map<String, dynamic>();
    _headers["api-version"] = "v1";
    _headers["Accept"] = "application/json";
    _headers["Content-Type"] = "application/json";
    _headers["Authorization"] = "Bearer ${await User.getToken()}";
    // _headers["Authorization"] =
    //     "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODAwMFwvYXBpXC9tZWRcL2F1dGhcL2xvZ2luIiwiaWF0IjoxNzEzNDA3MDkzLCJleHAiOjE3MTM0OTM0OTMsIm5iZiI6MTcxMzQwNzA5MywianRpIjoiRTlINTJwWHVjN1RibnpnYiIsInN1YiI6MSwicHJ2IjoiMjNiZDVjODk0OWY2MDBhZGIzOWU3MDFjNDAwODcyZGI3YTU5NzZmNyIsInJvbGUiOiJtZWRfdXNlciIsInZlcnNpb24iOjF9.m4LY1fnRvLgbmFmxFwQ6SRAMU61VdoaPIbR6wZhLsTY";
    Options options = Options(method: method.value, headers: _headers);
    // Response response = await _dio!.request(url,
    //     queryParameters: queryParameters, options: options, data: data);

    Response response;

    try {
      if (method == DioMethod.POST) {
        response = await _dio!.post(url,
            queryParameters: queryParameters,
            options: options,
            data: data,
            onSendProgress: onSendProgress);
      } else if (method == DioMethod.GET) {
        response = await _dio!.get(url,
            queryParameters: queryParameters, options: options, data: data);
      } else {
        /// 若是走该分支请留意，可能会报错，时间紧张这个分支，第一手代码者先不处理了，后续小伙伴处理吧
        "暂不支持该方式的请求${method}".toast();
        return;
      }
    } on DioException catch (err) {
      "请求异常：--->${_handleError(err)}".loge();
      if (failMsg != null) {
        failMsg("${_handleError(err)}");
      }
      return;
    } finally {
      // 关闭loading
      if (showLoading) {
        EasyLoading.dismiss();
      }
    }

    if (response.statusCode == 200) {
      /// Http响应码，非接口业务响应码，若是statusCode 非200 ，则需要把业务异常抛出去
      // json渲染json数据
      Map<String, dynamic> jsonData = jsonDecode(response.toString());
      // 获取接口响应码
      var resCode = jsonData['code'];
      // 判断业务响应吗是否为 0
      // 表示接口成功，解析data参数
      if (T.toString() == "dynamic" ||
          T.toString() == "Object?" ||
          T.toString() == "Null") {
        // 如果T不传或者T传值为Null,则data的返回值为 jsonData['data']
        BaseRes baseRes = BaseRes(
          code: resCode,
          message: jsonData['message'],
          data: jsonData['data'],
        );
        if (baseResponse != null) {
          baseResponse(baseRes);
        }
        if (success != null) {
          success(baseRes.data);
        }
      } else {
        // 解析data部分
        BaseRes baseRes = BaseRes<T>.fromJson(jsonData);
        // 对象数据结构
        if (baseRes.data != null) {
          if (success != null) {
            success(baseRes.data);
          }
        } else {
          if (failMsg != null) {
            failMsg("解析异常" ?? "");
          }
        }
        if (baseResponse != null) {
          baseResponse(baseRes);
        }
      }
    } else {
      // json渲染json数据
      Map<String, dynamic> jsonData = jsonDecode(response.toString());
      // 获取接口响应码
      var resMessage = jsonData['message'];
      var resCode = jsonData['code'];
      if (baseResponse != null) {
        "接口响应异常： resMessage：$resMessage".loge();
        // 表示接口不成功，不需要解析data参数
        BaseRes res = BaseRes(
          code: resCode,
          message: resMessage,
        );
        baseResponse(res);
      }
      if (failMsg != null) {
        failMsg(resMessage ?? "未知错误");
      }

      switch (resCode) {
        case HttpCode.login_timeout:
          User.clearToken();
          Get.offAllNamed(Routes.login);
          break;
        default:
          break;
      }
    }

    // return response.data;
  }
}

Future request<T>(String url,
    {DioMethod method = DioMethod.POST,
    Map<String, dynamic>? queryParameters,
    data,
    Map<String, dynamic>? headers,
    Function(T data)? success,
    Function(String errorMsg)? failMsg,
    Function(BaseRes baseResponse)? baseResponse,
    showLoading = false, // 默认显示网络加载loading
    loadingMsg = "加载中...", // loading文案
    toastFailMsg = true, // 默认吐司网络请求错误
    Function(int count, int total)? onSendProgress // 文件上传进度监听，只有Post方式才能回调该函数
    }) {
  return DioManager().request(url,
      method: method,
      queryParameters: queryParameters,
      data: data,
      headers: headers,
      success: success,
      failMsg: failMsg,
      baseResponse: baseResponse,
      onSendProgress: onSendProgress);
}

String _handleError(DioException e) {
  switch (e.type) {
    case DioExceptionType.cancel:
      return '请求被取消';
    case DioExceptionType.connectionTimeout:
      return '连接超时,请重试';
    case DioExceptionType.sendTimeout:
      return '请求超时、请重试';
    case DioExceptionType.receiveTimeout:
      return '响应超时,请重试';
    case DioExceptionType.badResponse:
      return '服务器响应错误';

    /// 例如 404,500， 报该错误时请慎重排查，也不一定是服务器错误哦。
    case DioExceptionType.connectionError:
      return '网络异常,请查看网络';
    default:
      return '未知错误: ${e.message}';
  }
}
